package services

import (
	"go-scripts/common"
	"github.com/go-redis/redis"
	"fmt"
	"sync"
)

var redisService *RedisService
//redis key列表
const (
	effectRank = "effectRank"
	test = "test"
	tmpInfoTime = "tmpInfoTime"
	tmpInfoCount = "tmpInfoCount"
	stkdata = "stk"
	effect = "effect"
	stocks = "stocks"
	zuiXinJia = "szxj"
	zhangFu = "szfr"
	remindLowLimit = "re:low"
	remindHighLimit = "re:high"
	remindLowPercentLimit = "re:lp"
	remindHighPercentLimit = "re:hp"
	topInfoRids = "topInfoRids"
)

type RedisService struct {
	dataRedis *redis.Client
	tokenRedis *redis.Client
	remindRedis *redis.Client
}

//初始化redisService
func GetRedisService() *RedisService {
	logger := common.GetLogger()
	if redisService != nil {
		return redisService
	}
	redisService := new(RedisService)
	//初始化redis连接
	r := common.GetRedis()
	fmt.Println("初始化redisService")
	var err error
	//以后可能有其他库，添加新的redisService即可
	redisService.dataRedis,err = r.GetRedisClient("data")
	redisService.tokenRedis,err = r.GetRedisClient("token")
	redisService.remindRedis,err = r.GetRedisClient("remind")
	if err != nil {
		logger.Fatal("初始化redis失败\n", err.Error())
	}
	return redisService
}
//获取redis key，用这个函数维护
func getRedisKey(keyName string, keyValue string) string {
	switch keyName {
	case effectRank:
		return effectRank
	case test:
		return test
	case tmpInfoTime:
		return tmpInfoTime
	case stkdata:
		return stkdata + ":" + keyValue
	case effect:
		return effect + ":" + keyValue
	case stocks:
		return stocks
	case zuiXinJia:
		return zuiXinJia
	case zhangFu:
		return zhangFu
	case remindLowLimit:
		return remindLowLimit
	case remindHighLimit:
		return remindHighLimit
	case remindLowPercentLimit:
		return remindLowPercentLimit
	case remindHighPercentLimit:
		return remindHighPercentLimit
	default:
		return ""
	}
}

type ZElement struct {
	Element string
	Score float64
}

type ZElementList []*ZElement

func (list ZElementList) Len() int {
	return len(list)
}

func (list ZElementList) Less(i, j int) bool {
	dif := list[i].Score - list[j].Score
	if dif < 0 {
		return true
	} else {
		return false
	}
}

func (list ZElementList) Swap(i, j int) {
	var tmp *ZElement = list[i]
	list[i] = list[j]
	list[j] = tmp
}

func (r* RedisService) SetTest(value string) error {
	dataRedis := r.dataRedis
	return dataRedis.Set(getRedisKey(test, ""), value, 0).Err()
}

func (r* RedisService) GetTest() string {
	dataRedis := r.dataRedis
	return dataRedis.Get(getRedisKey(test, "")).Val()
}
//这里的time为unix时间戳
func (r* RedisService) GetTmpInfoIdsByTime(min int64, max int64) []string {
	rangeBy := redis.ZRangeBy{
		Min:fmt.Sprintf("%d", min),
		Max:fmt.Sprintf("%d", max),
	}
	return r.dataRedis.ZRangeByScore(getRedisKey(tmpInfoTime, ""), rangeBy).Val()
}

func (r* RedisService) GetTmpInfoCountByIds(ids[] string) ZElementList {
	var wg sync.WaitGroup
	vals := []*ZElement{}
	for _,id := range ids {
		wg.Add(1)
		go func(task string) {
			defer wg.Done()
			vals = append(vals, &ZElement{
				Element: task,
				Score: r.dataRedis.ZScore(tmpInfoCount, task).Val(),
			})
		}(id)
	}
	wg.Wait()
	return vals
}

func (r* RedisService) GetStkKeys() []string {
	return r.dataRedis.Keys(getRedisKey(stkdata, "*")).Val()
}

func (r* RedisService) GetStockNameByECodes(eCodes[] string) []string {
	var wg sync.WaitGroup
	var mutex sync.Mutex
	names := []string{}
	for _,eCode := range eCodes {
		wg.Add(1)
		go func(task string) {
			defer wg.Done()
			name := r.dataRedis.HGet(getRedisKey(stkdata, task) , "ZhongWenJianCheng").Val()
			mutex.Lock()
			{
				names = append(names, name)
			}
			mutex.Unlock()
		}(eCode)
	}
	wg.Wait()
	return names
}

func (r *RedisService) GetEffectByHylandaIdAndDates(hylandaId string, dates[] string) ([]interface{}, error) {
	return r.dataRedis.HMGet(getRedisKey(effect, hylandaId), dates...).Result()
}

func (r *RedisService) GetStocks() ([]string, error) {
	return r.dataRedis.SMembers(getRedisKey(stocks, "")).Result()
}

func (r *RedisService) SaveStockPrice(price float64, eCode string) (int64, error) {
	return r.dataRedis.ZAdd(getRedisKey(zuiXinJia, ""), redis.Z{
		Score: price,
		Member: eCode,
	}).Result()
}

func (r *RedisService) SaveZhangFu(zhangDieFu float64, eCode string) (int64, error) {
	return r.dataRedis.ZAdd(getRedisKey(zhangFu, ""), redis.Z{
		Score: zhangDieFu,
		Member: eCode,
	}).Result()
}

func (r *RedisService) SaveStkData(eCode string, datas map[string]interface{}) (string, error) {
	return r.dataRedis.HMSet(getRedisKey(stkdata, eCode), datas).Result()
}

func (r *RedisService) GetRemindLimitValue(eCode string) []string {
	pipe := r.remindRedis.TxPipeline()
	low := pipe.HGet(getRedisKey(remindLowLimit, ""), eCode)
	high := pipe.HGet(getRedisKey(remindHighLimit, ""), eCode)
	lowPercent := pipe.HGet(getRedisKey(remindLowPercentLimit, ""), eCode)
	highPercent := pipe.HGet(getRedisKey(remindHighPercentLimit, ""), eCode)
	pipe.Exec()
	return []string{low.Val(), high.Val(), lowPercent.Val(), highPercent.Val()}
}

func (r *RedisService) SaveTmpInfoRids(rids []interface{})  {
	r.dataRedis.SAdd(topInfoRids, rids...)
}

func (r *RedisService) GetTopInfoRids() ([]string, error) {
	return r.dataRedis.SMembers(topInfoRids).Result()
}

func (r *RedisService) RemoveOneTopInfoRid(rid string) (int64, error) {
	return r.dataRedis.SRem(topInfoRids, rid).Result()
}